----------------------------------------------------------------
-- 竞技场db
----------------------------------------------------------------

local JjcExcel = require("excel.jjc")
local LuaMongo = _G.lua_mongo
local Config = require("Config")
local DB = require("common.DB")
local Util = require("common.Util")
local CommonDB = require("common.CommonDB")

local ObjHuman = require("core.ObjHuman")
local JjcLogic = require("jjc.JjcLogic")
local RoleDefine = require("role.RoleDefine")
local CombatDefine = require("combat.CombatDefine")
local CombatPosLogic = require("combat.CombatPosLogic")
local CombatVideo = require("combat.CombatVideo")
local CreateRole = require("role.CreateRole")

UUID_2_RANK = UUID_2_RANK or {}
RANK_2_JJCDATA = RANK_2_JJCDATA or {}
ROBOT_LIST = ROBOT_LIST or {}

MAX_RECORD_CNT = 5			-- 保留5条对战记录
SEASON_KEEP_DAY = 7 		-- 7天一个赛季
ROBOT_LIST_MAXLEN = 100     -- 100个机器人
JJC_INIT_POINT = 1000       -- 竞技场初始分

local QueryByUuid = {_id = nil}

function getRank(uuid)
	local index = UUID_2_RANK[uuid]
	return index or 0
end

function getJjcData(uuid)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
	return RANK_2_JJCDATA[rank]
end

function getJjcPoint(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return JJC_INIT_POINT
	end
	return jjcData.point
end

function getWorshipCnt(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return 0
	end
	return jjcData.worshipCnt
end

function getJjcTotalFight(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return 0
	end
	return jjcData.jjcTotalFight or 0
end

function getTotalFightCnt(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return 0
	end
	return jjcData.totalFightCnt or 0
end

function getJjcSeasonBox(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return {}
	end
	return jjcData.jjcSeasonBox or {}
end

function getJjcRival(uuid)
	local jjcData = getJjcData(uuid)
	if not jjcData then
		return {}
	end
	return jjcData.rival or {}
end

function isNpc(jjcData)
	if jjcData.point and jjcData.monsterOutID then
		return true
	end
end

function getSeasonCnt()
	local openDay = CommonDB.getServerOpenDay()
	if openDay == nil then return end

	return math.ceil(openDay / SEASON_KEEP_DAY)
end

function getSeasonEndTime()	
	local openDay = CommonDB.getServerOpenDay()
    local openServerTime = CommonDB.getServerOpenTime()
	if openDay == nil then return 0 end
    local championEndTime = CommonDB.getChampionEndTime()
    local nowTime = os.time()

    if championEndTime == 0 then
	    local dayStartTime = Util.getDayStartTime(openServerTime)
	    local endTime = dayStartTime + SEASON_KEEP_DAY * 86400 - 10800
        CommonDB.setChampionEndTime(endTime)
        championEndTime = endTime
    end
    local startTime = championEndTime - SEASON_KEEP_DAY * 86400
    local firstEndTime = SEASON_KEEP_DAY * 86400 + openServerTime - 10800
    if openDay <= SEASON_KEEP_DAY and firstEndTime == championEndTime then
        startTime = openServerTime
    end
	return championEndTime,startTime
end

function setSeasonEndTime()	
	local openDay = CommonDB.getServerOpenDay()
    local openServerTime = CommonDB.getServerOpenTime()
	if openDay == nil then return end
    local championEndTime = CommonDB.getChampionEndTime()
    if championEndTime == 0 then
        local nowTime = os.time()
	    local dayStartTime = Util.getDayStartTime(openServerTime)
	    championEndTime = dayStartTime + SEASON_KEEP_DAY * 86400 - 10800
    else
	    championEndTime = championEndTime + SEASON_KEEP_DAY * 86400
    end
    CommonDB.setChampionEndTime(championEndTime)
end

function getGodSeasonEndTime()
	local openTime = CommonDB.getServerOpenTime()
	if openTime == 0 then
		return
	end
	
	local nowTime = os.time()
	local dayStartTime = Util.getDayStartTime(openTime)
	local time = math.max(nowTime - dayStartTime, 1)	
	local openDay = math.ceil(time / 86400)
	local seasonCnt = math.ceil(openDay / SEASON_KEEP_DAY) - 1	

	local startTime = dayStartTime + seasonCnt * SEASON_KEEP_DAY * 86400 
	local seasonStartTime = startTime - 3 * 3600
	local seasonEndTime = seasonStartTime + SEASON_KEEP_DAY * 86400
	if nowTime > seasonEndTime then
		seasonStartTime = seasonEndTime
		seasonEndTime = seasonStartTime + SEASON_KEEP_DAY * 86400
	end
	return seasonEndTime, math.max(seasonStartTime, openTime), startTime
end

function updateJJCData(jjcData)
	if not jjcData._id then return end
	QueryByUuid._id = jjcData._id
	LuaMongo.update(DB.db_jjc, QueryByUuid, jjcData)
end

function removeJJCData(uuid)
	if not uuid then return end
	QueryByUuid._id = uuid
	LuaMongo.remove(DB.db_jjc, QueryByUuid)
end

function initJJCDB()
	RANK_2_JJCDATA = {}
	UUID_2_RANK = {}
	ROBOT_LIST = {}
	resetJJCDB(true)
end

function isEmpty()
    LuaMongo.find(DB.db_jjc)
	local data = {}
	if not LuaMongo.next(data) then    
		return true
	end	
end

function resetJJCDB(init)
	-- 删除假人 留下真人
	ROBOT_LIST = {}
	UUID_2_RANK = {}	
	local count = #RANK_2_JJCDATA
	local reallyCount = 0
	for i = 1, count do
		local jjcData = RANK_2_JJCDATA[i]
		RANK_2_JJCDATA[i] = nil
		if isNpc(jjcData) and init then			
			removeJJCData(jjcData._id)
		else
			jjcData.point = math.floor(jjcData.point*7/10)
            if jjcData.point < JJC_INIT_POINT then
                jjcData.point = JJC_INIT_POINT
            end
			jjcData.recordList = nil
			jjcData.jjcSeasonBox = {}
			jjcData.rival = nil
			jjcData.jjcTotalFight = 0
			jjcData.worshipCnt = 0
			reallyCount = reallyCount + 1
			RANK_2_JJCDATA[reallyCount] = jjcData
			updateJJCData(jjcData)
		end
	end
	CombatVideo.cleanJJCVideo()

	-- 插入假人
    if init then
	    for _, npcConfig in ipairs(JjcExcel.npc) do
	    	for i = 1, npcConfig.cnt do
	    		addNpc(npcConfig)
	    	end
	    end
    end
	sortRank()
end

function loadJJCData()
    LuaMongo.find(DB.db_jjc)
    while true do
    	local data = {}
    	if not LuaMongo.next(data) then    
    		break
    	end	

    	if data.point then
    		RANK_2_JJCDATA[#RANK_2_JJCDATA + 1] = data
    	else
    		return
    	end
    end
    sortRank()
    for i = 1, #RANK_2_JJCDATA do
    	if #ROBOT_LIST >= ROBOT_LIST_MAXLEN then
    		break
    	end
    	local jjcData = RANK_2_JJCDATA[i]
    	if isNpc(jjcData) then
			ROBOT_LIST[#ROBOT_LIST + 1] = jjcData   		
    	end
    end
    return true
end

function initAfterStart()
    if _G.is_middle == true then return end

    -- 检查赛季
    checkReset()
    checkSeasonTime()
    if isEmpty() then
    	initJJCDB()
    else
    	loadJJCData()
    end
end

local function ownCmp(a, b)
	if a.point ~= b.point then
		return a.point > b.point
	end
	return a.time < b.time
end

function sortRank()
	if #RANK_2_JJCDATA > 1 then
		table.sort(RANK_2_JJCDATA, ownCmp)
	end
	for rank = 1, #RANK_2_JJCDATA do
		local uuid = RANK_2_JJCDATA[rank]._id
		UUID_2_RANK[uuid] = rank
	end
end

function addPlayer(human)
	local rank = UUID_2_RANK[human.db._id]
	if rank then return end

	local jjcData = {}
	jjcData._id = human.db._id
	jjcData.point = JJC_INIT_POINT
	jjcData.recordList = nil
	jjcData.totalFightCnt = 0  -- 为所有赛季战斗次数总和，超过20次则不再累计,赛季结束不清0
	jjcData.time = os.time()
	LuaMongo.insert(DB.db_jjc, jjcData)
	
	RANK_2_JJCDATA[#RANK_2_JJCDATA + 1] = jjcData
	sortRank()
end

function addNpc(config)
	local jjcData = {}
	local r = math.random(1, #config.monsterOutID)
	jjcData.monsterOutID = config.monsterOutID[r]
	jjcData.lv = 20
    jjcData.head = CreateRole.getRandomHead()    
	jjcData.name = CreateRole.getRandomName()
	jjcData.body = CreateRole.getRandomBody()
	jjcData.identity = CreateRole.getFakeIdentityMax()
	jjcData.point = config.initPoint
	jjcData.zhandouli = math.random(config.zhandouli[1], config.zhandouli[2])
	jjcData.time = os.time()
	LuaMongo.insert(DB.db_jjc, jjcData)
	RANK_2_JJCDATA[#RANK_2_JJCDATA + 1] = jjcData
	
	if #ROBOT_LIST < ROBOT_LIST_MAXLEN then
		ROBOT_LIST[#ROBOT_LIST + 1] = jjcData
	end
end

function updatePlayerPoint(uuid, point, nosort)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
	if jjcData.point == point then
		return
	end		
	jjcData.point = point
	jjcData.time = os.time()
	updateJJCData(jjcData)

	if not nosort then
		sortRank()
	end
end

-- 更新总战斗次数
function updateTotalFight(uuid)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
    jjcData.jjcTotalFight = jjcData.jjcTotalFight or 0
	jjcData.jjcTotalFight = jjcData.jjcTotalFight + 1
	updateJJCData(jjcData)
end

-- 更新所有赛季总战斗次数
function updateTotalFightCnt(uuid)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
    jjcData.totalFightCnt = jjcData.totalFightCnt or 0
    if jjcData.totalFightCnt >= 20 then
        return
    end
	jjcData.totalFightCnt = jjcData.totalFightCnt + 1
	updateJJCData(jjcData)
end

-- 更新总膜拜次数
function updateWorshipCnt(uuid)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
    jjcData.worshipCnt = jjcData.worshipCnt or 0
	jjcData.worshipCnt = jjcData.worshipCnt + 1
	updateJJCData(jjcData)
end

-- 更新赛季盒子信息
function updateSeasonBox(uuid,index)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
	if jjcData.jjcSeasonBox and jjcData.jjcSeasonBox[index] ~= nil then
		return
	end		
    jjcData.jjcSeasonBox = jjcData.jjcSeasonBox or {}
	jjcData.jjcSeasonBox[index] = 2
	updateJJCData(jjcData)
end

-- 更新对手
function updateRival(uuid,index,uuid2)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
    jjcData.rival = jjcData.rival or {}
	jjcData.rival[index] = uuid2
	updateJJCData(jjcData)
end

-- 清空对手
function cleanRival(uuid)
	local rank = UUID_2_RANK[uuid]
	if not rank then return end
		
	local jjcData = RANK_2_JJCDATA[rank]
	if jjcData.rival and jjcData.rival[index] ~= nil then
		return
	end		
    jjcData.rival = nil
	updateJJCData(jjcData)
end

local function addRocord(jjcData, videoUuid)
	if isNpc(jjcData) then return end

	jjcData.recordList = jjcData.recordList or {}
	table.insert(jjcData.recordList, 1, videoUuid)

	
	local removeUuid = jjcData.recordList[MAX_RECORD_CNT + 1]
	if removeUuid then
		jjcData.recordList[MAX_RECORD_CNT + 1] = nil
		CombatVideo.delJJCVideoCnt(removeUuid)
	end
	updateJJCData(jjcData)
end

local QueryByUuidAtk = {}
function addJjcRecord(atkUuid, defUuid, combatInfo)	
	local atkData = getJjcData(atkUuid)
	local defData = getJjcData(defUuid)
	if not atkData or not defData then return end

	local cnt = (not isNpc(atkData)) and 1 or 0
	cnt = cnt + ((not isNpc(defData)) and 1 or 0 )

	if cnt < 1 then return end
	local combatVideo = CombatVideo.createCombatVideo(CombatVideo.VIDEOTYPE_JJC, combatInfo, cnt)
	if not combatVideo then return end

	addRocord(atkData, combatVideo._id)
	addRocord(defData, combatVideo._id)
end

function getJjcRecordList(uuid)
  	local jjcData = getJjcData(uuid)
  	if not jjcData then return end
  	return jjcData.recordList  
end

function checkReset()
    local endTime = getSeasonEndTime()	
    local now = os.time()
    if now >= endTime then
        resetJJCDB()
        setSeasonEndTime()
    end
end

function checkSeasonTime()
    local endTime = getSeasonEndTime()	
    local openServerTime = CommonDB.getServerOpenTime()
    if openServerTime == 0 then
        -- 备服，服务器启动中，但服务器未开放
        -- 清除已计算的竞技场时间
        CommonDB.setChampionEndTime()
        return
    end
    
    local now = os.time()

    local day = Util.diffDayByTimes(openServerTime,now)
    local trueDay = day + 1

    local day2 = trueDay % SEASON_KEEP_DAY
    local day3 = 0

    if day2 ~= 0 then
        day3 = SEASON_KEEP_DAY - day2
    end

    local dayStartTime = Util.getDayStartTime(now)

    local trueEndTime = dayStartTime + day3*86400 + 21*60*60
    CommonDB.setChampionEndTime(trueEndTime)
end

function cleanOldVideos()
	local delTime = os.time() - 3*86400 -- 删除三天前的记录
	local field = {["combatInfo.time"]=1}
	for rank, jjcData in ipairs(RANK_2_JJCDATA) do
		local recordLen = jjcData.recordList and #jjcData.recordList or 0
		local realRecordLen = 0
		for i = 1, recordLen do
			local videoUuid = jjcData.recordList[i]
			jjcData.recordList[i] = nil 
			local combatVideo = CombatVideo.getCombatVideo(videoUuid, field)
			if combatVideo and combatVideo.combatInfo.time > delTime then
				realRecordLen = realRecordLen + 1
				jjcData.recordList[realRecordLen] = videoUuid
			else
				CombatVideo.removeCombatVideo(videoUuid)
			end
		end
		if recordLen ~= realRecordLen then
			updateJJCData(jjcData)
		end
	end
end